<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script>
      /**
       * Generator函数是协程在es6的实现，最大的特点就是可以交出函数的执行权(即暂停执行)
       * 整个Generator函数就是一个封装的异步任务，或者说，异步任务的容器。异步操作需要暂停的地方，都用yeild语句注明
       */
      function* gen(x) {
        var y = yield x + 2;
        return y;
      }
      var g = gen(1);
      g.next(); // { value: 3, done: false }
      g.next(); // { value: undefined, done: true }
      /**
       * 上面代码中，调用Generator函数，会返回一个内部指针，(即遍历器g)
       * 这是Generator函数不同于普通函数的另一个地方，即执行它不会返回结果，返回的是指针对象，
       * 调用指针g的next方法，会移动内部指针，即执行异步任务的第一段。
       * 指向第一个遇到的yeild语句，上例是执行到x +2 为止。
       *
       * 换言之，next方法的作用是分阶段执行Generator函数，每次调用next方法，会返回一个对象
       * 表示当前阶段的信息
       */
    </script>
    <script>
      // Generator函数可以暂停执行和恢复执行，这是它能封装异步任务的根本原因。。。
      /**
       * 除此之外，它还有俩个特性，可以使它作为异步编程的完整解决方案
       *
       * --函数体外的数据交换
       * --函数体外的错误处理机制
       *
       * next返回的value属性，是Generator函数向外部输出的数据；
       * next方法还可以接受参数，向Generator函数体内输入数据
       */
      function* gen(x) {
        var y = yield x + 2;
        return y;
      }

      var g = gen(1);
      g.next(); // { value: 3, done: false }
      g.next(2); // { value: 2, done: true }
      /**
       * 上面代码中，第一个next方法的value属性，返回表达式x + 2的值3。
       * 第二个next方法带有参数2，这个参数可以传入 Generator 函数，
       * 作为上个阶段异步任务的返回结果，被函数体内的变量y接收。因此，这一步的value属性，返回的就是2（变量y的值）。
      */
     // Generator函数内部还可以部署错误处理代码，捕获函数体外抛出的错误。
     function* foo(x) {
       try {
         var y = yield x + 2;
       } catch (error) {
         console.log('错误信息', error)
       }
       return y;
     }
     var f = foo(1);
     f.next();
     f.throw('我错了，下次还敢')
     /**
      * 上面代码的最后一行，Generator 函数体外，使用指针对象的throw方法抛出的错误，可以被函数体内的try...catch代码块捕获。
      * 这意味着，出错的代码与处理错误的代码，实现了时间和空间上的分离，这对于异步编程无疑是很重要的。
     */
    </script>
  </body>
</html>
